package com.seahorse.youliao.listenter;

import com.seahorse.youliao.service.SysLoginLogService;
import com.seahorse.youliao.service.entity.SysLoginLogDTO;
import com.seahorse.youliao.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * @ProjectName: youliao
 * @Package: com.seahorse.youliao.listenter
 * @ClassName: AuthenticationEventLogger
 * @Description: springsecurity事件监听
 * @author:songqiang
 * @Date:2020-11-26 16:24
 **/
@Component
public class AuthenticationEventLogger implements ApplicationListener<AbstractAuthenticationEvent> {


    @Autowired
    private SysLoginLogService loginLogService;

    /**
     *  AbstractAuthenticationFailureEvent 在验证过程中发生异常会触发此类事件（抽象类型）,
     *
     *  AuthenticationFailureBadCredentialsEvent（提供的凭据是错误的，用户名或者密码错误）
     *
     *  AuthenticationFailureCredentialsExpiredEvent（验证通过了，但是密码已经过期）
     *
     *  AuthenticationFailureDisabledEvent（验证过了但是账户被禁用）
     *
     *  AuthenticationFailureExpiredEvent(账户过期）,
     *
     *  AuthenticationFailureLockedEvent（账户被锁定）,
     *
     *  AuthenticationFailureProviderNotFoundEvent（配置错误，没有合适的AuthenticationProvider来处理登录验证）
     *
     *  AuthenticationFailureProxyUntrustedEvent（代理不受信任，用于Oauth、CAS这类三方验证的情形，多属于配置错误）,
     *
     *  AuthenticationFailureServiceExceptionEvent（其他任何在AuthenticationManager中发生的异常都会被封装成此类，表示服务器500错误）
     *
     *  AuthenticationSuccessEvent（用户通过输入用户名和密码登录成功）,
     *
     *  AuthenticationSwitchUserEvent（通过切换用户的手段来登录）,
     *
     *  InteractiveAuthenticationSuccessEvent,（同样是登录成功，但表示通过自动交互的手段来登录成功，比如cookie自动登录）
     *
     *  SessionFixationProtectionEvent（当发生session fixation 攻击时触发的事件）
     * @param abstractAuthenticationEvent
     */
    @Override
    public void onApplicationEvent(AbstractAuthenticationEvent abstractAuthenticationEvent) {

        if(abstractAuthenticationEvent instanceof InteractiveAuthenticationSuccessEvent){

            //登录成功 记录日志 或增加额外业务操作
            UserDetails userDetails = (UserDetails)abstractAuthenticationEvent.getAuthentication().getPrincipal();
            insertLoginLog(userDetails.getUsername());

        }

    }


    /**
     * 记录登录日志
     * @param userName
     */
    private void insertLoginLog(String userName) {

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();
        //记录登录日志
        SysLoginLogDTO loginLogDTO = new SysLoginLogDTO();
        loginLogDTO.setLoginName(userName);
        String ip = IpUtil.getIpAddr(request);
        loginLogDTO.setIp(ip);
        loginLogDTO.setLoginLocation(IpUtil.getCityInfo(ip));
        loginLogDTO.setBrowser(IpUtil.getBrowser(request));
        loginLogDTO.setOs(IpUtil.getOperatingSystem(request));
        loginLogDTO.setStatus(0);
        loginLogDTO.setLoginTime(new Date());
        loginLogService.insert(loginLogDTO);
    }
}
